import { connect } from 'dva';
import * as THREE from 'three'
import { useEffect, useRef, useState } from 'react';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { Water } from 'three/examples/jsm/objects/Water2.js'
import * as TWEEN from 'three/examples/jsm/libs/tween.module.js'

 const TestPage = (props) => {
   const sceneRef = useRef(null)
   const cameraRef = useRef(null)
   const rendererRef = useRef(null)
   const guiRef = useRef(null)
   let tween = null
   const width = 1000; //宽度
   const height = 800; //高度
   const scenes = [
       {
           text: '一下',
           callback: ()=>{
               // 不生效，因为controls轨道控制器控制了相机，会冲突，可以选择用gasp动画库改变相机位置
               tween.to({ x: 40, y: 40, z: 10}, 1500).onUpdate(()=>{
                console.log(cameraRef.current.position,'999')
               })
               tween.easing(TWEEN.Easing.Quadratic.InOut)
           }
       },
       {
        text: '两下',
        callback: ()=>{
            tween.to({ x: 80, y: 20, z: 29}, 1500)
            tween.easing(TWEEN.Easing.Quadratic.InOut)
        }
    },
    {
        text: '三下',
        callback: ()=>{
            tween.to({ x: -10, y: 20, z: -6}, 1500)
            tween.easing(TWEEN.Easing.Quadratic.InOut)
        }
    },
    {
        text: '四下',
        callback: ()=>{
            tween.to({ x: 140, y: 140, z: -10}, 1500)
            tween.easing(TWEEN.Easing.Quadratic.InOut)
        }
    }
   ]
   let index = useRef(0)
   useEffect(()=>{
    init()

    window.addEventListener("wheel",(e)=>{
        // 向上滑动
        if(e.deltaY > 0) {
            index.current++;
            if(index.current > scenes.length - 1){
                index.current = 0;
            } 
        }
        tween = new TWEEN.Tween(cameraRef.current.position);
        scenes[index.current].callback()
    }, false)
   }, [])
   const init = () => {
      // 0.添加GUI
      const eventObj = {
        Fullscreen: function(){
         document.body.requestFullscreen()
        },
        Exitscreen: () => {
          document.exitFullscreen()
        }
      }
      guiRef.current = new GUI()
      guiRef.current.add(eventObj, "Fullscreen").name('全屏')
      guiRef.current.add(eventObj, "Exitscreen").name('退出全屏')

      // 1.创建3D场景对象Scene
      sceneRef.current = new THREE.Scene();

      // 4.创建物体
      setGeometry()

      // 2. 定义虚拟相机部分
      setCamera()

      // 5. 坐标辅助器
      const axesHelper = new THREE.AxesHelper(500)
      sceneRef.current.add(axesHelper)

      // 3.渲染器
      setRenderer()

      // 全屏 rendererRef.current.domElement.requestFullscreen()
      window.addEventListener("resize",()=>{
        rendererRef.current.setSize(window.innerWidth,window.innerHeight);
        cameraRef.current.aspect = window.innerWidth/window.innerHeight;
        cameraRef.current.updateProjectionMatrix()
      })

   }

   // 创建相机
   const setCamera = () => {
      // width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
      cameraRef.current = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
      // 实例化一个透视投影相机对象
      // 根据需要设置相机位置具体值
      cameraRef.current.position.set(80, 80, 0);
      cameraRef.current.lookAt(0,0,0);//指向mesh对应的位置

      tween = new TWEEN.Tween(cameraRef.current.position);
   }
   // 创建几何体
   const setGeometry = () => {
      //  example 1：灯光
      getGeomery()   
   }
   // 创建渲染器
   const setRenderer = () => {
      // 创建渲染器对象
      rendererRef.current = new THREE.WebGLRenderer();
      rendererRef.current.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
      rendererRef.current.shadowMap.enabled = true; //开启阴影
      rendererRef.current.physicallyCorrectLights = true;//聚光灯decay
      rendererRef.current.render(sceneRef.current, cameraRef.current); //执行渲染操作
      document.getElementById('webgl').appendChild(rendererRef.current.domElement);

      // 色调映射
      rendererRef.current.outputEncoding = THREE.sRGBEncoding;
      rendererRef.current.toneMapping = THREE.ACESFilmicToneMapping;
      rendererRef.current.toneMappingExposure = 0.8;
      // 6. 轨道控制器
      const controls = new OrbitControls(cameraRef.current, rendererRef.current.domElement)
     
      function animate(){
        requestAnimationFrame(animate)
        controls.update()
        rendererRef.current.render(sceneRef.current, cameraRef.current)
      }
      animate()
   }
   // 平面
   const getGeomery = () => {
       sceneRef.current.background = new THREE.Color(0xd0eefb)
     // 1. 环境光 AmbientLight（没有环境贴图）
     const ambientLight = new THREE.AmbientLight(0xfefefe, 0.5);
     sceneRef.current.add(ambientLight)
     // 2. 导入模型
     let cubes = []; //立方体
     let cubeMaterial = new THREE.MeshPhysicalMaterial({ //物理材质
        color: 0x898b89,
        metalness: 1, //金属度
        roughness: 0.8, // 粗糙程度，一定的反光,0是没有反光
        clearcoat: 1, //喷漆
        clearcoatRoughness: 0, // 喷漆的光滑度，0是最光滑
     })
     let grasses = []; // 草
     let grassMaterial = new THREE.MeshPhysicalMaterial({ //物理材质
        color: 0x027e02,
        metalness: 1, //金属度
        roughness: 0.1, // 粗糙程度，一定的反光,0是没有反光
     })
     let mushroomMaterial = new THREE.MeshPhysicalMaterial({ //物理材质
        color: 0xe27f55,
        metalness: 1, //金属度
        roughness: 0.4, // 粗糙程度，一定的反光,0是没有反光
     })
     let mushrooms = []; //蘑菇
     let planes = [];
     // 玻璃材质，透亮
     let planesMaterial = new THREE.MeshPhysicalMaterial({ //物理材质
        color: 0x097709,
        metalness: 0, //金属度
        roughness: 0.1,
        transmission: 1,
        transparent:true,
     })
     let zhutis = [];
     let zhutiMaterial = new THREE.MeshPhysicalMaterial({ //物理材质
        color: 0x6080e2,
        metalness: 0.8, //金属度
        roughness: 0.5,
        clearcoat: 1, //喷漆
        clearcoatRoughness: 0, // 喷漆的光滑度，0是最光滑
     })
     let yuanhuans = [];
     let yuanhuanMaterial = new THREE.MeshPhysicalMaterial({ //物理材质
        color: 0xd4ff00,
        metalness: 0.8, //金属度
        roughness: 0.5,
        clearcoat: 1, //喷漆
        clearcoatRoughness: 0, // 喷漆的光滑度，0是最光滑
        transmission: 0.6,
        transparent:true,
     })
     let trees = [];
     let treeMaterial = new THREE.MeshBasicMaterial({ //物理材质
        color: 0x3f883f,
     })
     let treestumps = [];
     let treestumpsMaterial = new THREE.MeshPhysicalMaterial({ //物理材质
        color: 0x11a611,
        metalness: 0.3, //金属度
        roughness: 0.5,
        transmission: 0.6,
        transparent:true,
     })
     let foxs = [];
     let foxsMaterial = new THREE.MeshPhysicalMaterial({ //物理材质
        color: 0xff0000,
        metalness: 0.8, //金属度
        roughness: 0.5,
        clearcoat: 1, //喷漆
        clearcoatRoughness: 0, // 喷漆的光滑度，0是最光滑
        transmission: 0.6,
        transparent:true,
     })
     const gltfLoader = new GLTFLoader();
      gltfLoader.load(require('.././assets/model/test.glb'),(glb)=>{
        console.log(glb)
        const model = glb.scene;
        model.traverse((child)=>{
            if(child.isMesh){
                console.log(child.name, '---name')
                if(child.name == 'dimian'){
                    child.visible = false
                } 
                child.castShadow = true;
                child.receiveShadow = true;   
                // 给不同的物体加材质
                if(child.name.includes("立方体")){
                    cubes.push(child)
                    child.material = cubeMaterial;    
                }
                if(child.name.includes("mushroom") || child.name.includes("球体")){
                    mushrooms.push(child);
                    child.material = mushroomMaterial;
                }
                if(child.name.includes("细草sample") || child.name.includes("草堆")){
                    grasses.push(child);
                    child.material = grassMaterial;
                }
                if(child.name.includes("平面")){
                    planes.push(child);
                    child.material = planesMaterial;
                }
                if(child.name.includes("柱体")){
                    zhutis.push(child);
                    child.material = zhutiMaterial;
                }
                if(child.name.includes("圆环") || child.name.includes("skin_tree")){
                    yuanhuans.push(child);
                    child.material = yuanhuanMaterial;
                }
                if(child.name.includes("树叶") || child.name.includes("guibeizhu")){
                    trees.push(child);
                    child.material = treeMaterial;
                }
                if(child.name.includes("treestump") || child.name.includes("treetrunk")){
                    treestumps.push(child);
                    child.material = treestumpsMaterial;
                }
                if(child.name.includes("moss")){
                    treestumps.push(child);
                    child.material = treestumpsMaterial;
                }  
                if(child.name.includes("棱角球")){
                    treestumps.push(child);
                    child.material = treestumpsMaterial;
                }
                if(child.name.includes("fox") || child.name.includes("leaves")){
                    foxs.push(child);
                    child.material = foxsMaterial;
                }
            }
        }) 
        sceneRef.current.add(glb.scene)
      })
      // 2. 自定义个地面（水面当地面）
      const dimianGeometry = new THREE.CircleGeometry(30, 32)
      const water = new Water(dimianGeometry, {
          textureWidth: 1024,
          textureHeight: 1024,
          color: 0x00fffb,
          flowDirection: new THREE.Vector2(1,1), //水流方向
          scale: 5,  // 靠近水流还是远离水流
      })
      sceneRef.current.add(water)
      // 默认平面是竖着的，所以能看到倒影，需要旋转
      water.rotation.x = -Math.PI /2;
      water.position.set(40,-3,0)
    // 模拟灯泡组（将点光源赋到一个小球上）
    const pointLightGroup = new THREE.Group();
    let radius = 25; //绕着这个半径旋转
    for(let i =0;i<3;i++){
        const lightBall = new THREE.Mesh(
            new THREE.SphereGeometry(0.5,32,32),
            new THREE.MeshStandardMaterial({color: 0xff0000})
        )
        // 三个方向，就是三角函数-1,0,1的计算,相同角度Math.cos与Math.sin值正好相反
        lightBall.position.set(
            radius * Math.cos((i*2*Math.PI)/3),
            Math.cos((i*2*Math.PI)/3)+radius,
            radius * Math.sin((i*2*Math.PI)/3)
        )
        const pointLight = new THREE.PointLight(0xffffff, 1);
        pointLight.castShadow = true;
        pointLight.decay = 0
        lightBall.add(pointLight)
        pointLightGroup.add(lightBall)
    }
    sceneRef.current.add(pointLightGroup)
    let colorParams = {
        cubeColor: '#00ff00'
      }
    guiRef.current.addColor(colorParams, "cubeColor").name('颜色辅助器')
    //  guiRef.current.add(pointLight,"distance").min(0).max(10).step(0.01)
    //  guiRef.current.add(pointLight,"decay").min(0).max(10).step(0.01)
    // 多个星星
    getMultiSphere()
   }
   // 满天星
   const getMultiSphere = () => {
    // 1. 创建100个球
       let starsInstance = new THREE.InstancedMesh(
           new THREE.SphereGeometry(0.15,32,32),
           new THREE.MeshStandardMaterial({
               color: 0x000000,
               emissive: 0x000000,
               emissiveIntensity: 10,
           }),
           100
       )
    // 2. 随机撒满
    let startArr = [];
    let endArr = [];
    for(let i = 0;i< 100;i++){
        let x = Math.random() * 100 -50;
        let y = Math.random() * 100 -50;
        let z = Math.random() * 100 -50;
        startArr.push(new THREE.Vector3(x,y,z))

        // 因为物体能位移、旋转、缩放，所以将变量放置物体矩阵
        let matrix = new THREE.Matrix4();
        matrix.setPosition(x,y,x);
        starsInstance.setMatrixAt(i, matrix)
    }
    sceneRef.current.add(starsInstance)

    // 3. 使用贝塞尔曲线画爱心路径，看官网API抄
    setTimeout(()=>{
        let heartShape = new THREE.Shape();
        heartShape.moveTo(25,25);
        heartShape.bezierCurveTo(25,25,20,0,0,0);
        heartShape.bezierCurveTo(-30,0,-30,35,-30,35);
        heartShape.bezierCurveTo(-30,55,-10,77,25,95);
        heartShape.bezierCurveTo(60,77,80,55,80,35);
        heartShape.bezierCurveTo(80,35,80,0,50,0);
        heartShape.bezierCurveTo(35,0,25,25,25,25);
    
        // 4. 根据爱心路径获取100个点
        for(let i = 0;i< 100;i++){
            let point = heartShape.getPoint(i/100);
            endArr.push(new THREE.Vector3(point.x, point.y, point.z))
    
            // 因为物体能位移、旋转、缩放，所以将变量放置物体矩阵
            let matrix = new THREE.Matrix4();
            matrix.setPosition(endArr[i].x-15, endArr[i].y-15, endArr[i].z-15);
            starsInstance.setMatrixAt(i, matrix)
        }

        starsInstance.instanceMatrix.needsUpdate = true
    }, 3000)
    
   }

  return (
    <div>
      <div id="webgl"></div>
    </div>
  );
}
export default connect(({common})=>({
  userInfo: common.userInfo,
}))(TestPage)